//
// create closure
//
(function($) {
	//
	// plugin definition
	//
	$.fn.drawio = function(options) {
		// build main options before element iteration
		var opts = $.extend({}, $.fn.drawio.defaults, options);
		// iterate over each matched element
		return this.each(function() {
			$this = $(this);
			// build element specific options
			var o = $.metadata ? $.extend({}, opts, $this.metadata()) : opts;
			
			// TODO: Add support for when <canvas> isn't available
			
			// Create the canvas element
			var $canvas = jQuery("<canvas width=\"" + o.width + "\" height=\"" + o.height +"\"></canvas>");
		
			// Use this composite operation to make it so that you can clear the background to full transparency
			//$canvas.get(0).getContext("2d").globalCompositeOperation = "copy";
		
			// Attach history string to canvas element
			$canvas.data('history',[]);
			
			// copy over id and class attributes
			$canvas.attr('id',$this.attr('id'));
			$canvas.attr('class',$this.attr('class'));
			$canvas.attr('saving',false);
			
			// replace the matched element with the canvas element
			$this.replaceWith($canvas);
			
			// Add auto sync call back timer
					
			// setup events (Create inside closure to store/hide private vars)
			
			(function(){
				var	mDown = false,dragStartX,dragStartY,prevDragX,prevDragY,count;
				function createAutoLoadCB($canvas)
				{
					var timerID;
					var unique = $.fn.drawio.timerCount+1;
					$.fn.drawio.timerCount++;
				//	console.log($.fn.drawio.timerCount);
					$.fn.drawio["cb"+unique] = function()
					{
						if(timerID)
					      clearTimeout(timerID);
					//	  console.log($canvas.attr('saving'));
						//  console.log(mDown);
						var a = !mDown&&!!$canvas.attr('saving');
					//	console.log( a );
						
						if(a)
						{
							load($canvas,getAttribute($canvas,'urlLoad'));
						}
						//alert($this);
						
						//alert(unique);
						//timerID = setTimeout("jQuery.fn.drawio.cb"+unique+"()", (1000));
					}
					// start timer
					timerID = setTimeout("jQuery.fn.drawio.cb"+unique+"()", 10);
				}
				
				
				$canvas.mousedown(function (event){
					// was already down?
					if(mDown)
						return;
						
					//  Store down state and prevent default action and event bubbling
					mDown = true;
					count = 0;
					event.preventDefault();
					event.stopPropagation();
					
					event.pageX -= getClientOffset(this).x;
					event.pageY -= getClientOffset(this).y;
					
					// record history in string format
					var history = $canvas.data('history');
				//	debug(history);
					history.push([
						$.fn.drawio.defaults.fill,[event.pageX,event.pageY]
					]);
					$canvas.data('history',history);
					
					dragStartX = event.pageX;
					dragStartY = event.pageY;
					prevMouseX = dragStartX;	
					prevMouseY = dragStartY;	
				});
				$canvas.mousemove(function (event){
				//	debug("mouse is moving");
					if(mDown)
					{			
					//	debug(this.id);
					
						event.preventDefault();
						event.stopPropagation();
					
						event.pageX -= getClientOffset(this).x;
						event.pageY -= getClientOffset(this).y;
					
						count+=1;
						
						line(this.getContext("2d"),$.fn.drawio.defaults.fill,{x:prevMouseX,y:prevMouseY},{x:event.pageX,y:event.pageY});
						
						// record history in string format
							// Add another point to the list
						var history = $canvas.data('history');
						history[history.length-1].push(
							[event.pageX,event.pageY]
						);
						$canvas.data('history',history);
																					
						prevMouseX = event.pageX;
						prevMouseY = event.pageY;
					}
				});
				$canvas.mouseup(function (event){
					if(!mDown)
						return;
						//alert("hi");
					event.preventDefault();
					event.stopPropagation();
					
					// save on mouse up
					$this = $(this);
					
					if(count>0)
						save($this,getAttribute($this,'urlSave'));
					
					count = 0;
					
					mDown = false;
				});
				$canvas.blur(function (event){
					// reset state if we lose focus
						// this makes sure we don't get in a state where the mouse is up, but the code missed the mouseup event
						//(this can happen for example when another application pops up over the browser while we are dragging the mouse
					mDown = false;
				});
				$canvas.dblclick(function (event){
					$this = $(this);
					// use options if no clear color is passed in 		
					// TODO: Make it use the default colors correctly
					$this.data('history',[]);
					color = getAttribute($this,'clear');
					clear(this.getContext("2d"),color,$this.attr('width'),$this.attr('height'));
					
					save($this,getAttribute($this,'urlSave'));
					
				});
				$canvas.keypress(function (event){
					alert(event.which);
					if(event.which!=46)
						return;
						
					event.preventDefault();
					event.stopPropagation();
					
					$this = $(this);
					// use options if no clear color is passed in 		
					// TODO: Make it use the default colors correctly
					color = getAttribute($this,'clear');
					clear(this.getContext("2d"),color,$this.attr('width'),$this.attr('height'));					
				});
				createAutoLoadCB($canvas);
			})();
			
			
		});
	};
	$.fn.drawio.timerCount=0;
  
	//
	// private functions

	//  debugging
	function debug($txt) {
		if (window.console && window.console.log)
			window.console.log($txt);
	};
	
	//
	// private internal implementations
	
	// does the logic of figuring out which attribute value to use
	//	defaults, metadata, or user supplied
	function getAttribute($this,attr,value)
	{
		if(value==undefined)
			value = ($.metadata && $this.metadata()[attr])?$this.metadata()[attr]:$.fn.drawio.defaults[attr];
		return value;
	}
	
	// calculate client offset(there must be a better way)
	function getClientOffset(e)
	{
		var 	xPos = e.offsetLeft,
				yPos = e.offsetTop;
		
		var 	tempEl = e.offsetParent;
		while (tempEl != null) {
			xPos += tempEl.offsetLeft;
			yPos += tempEl.offsetTop;
			tempEl = tempEl.offsetParent;
		}
		return {x: xPos, y: yPos};
	}
	
	function clear(ctx,color,width,height)
	{
		// Fill
		ctx.fillStyle = color;
		ctx.fillRect (0, 0, width, height);
	}
	
	function pixel(ctx,color,x,y)
	{	
		ctx.fillStyle = color;
		ctx.fillRect (x, y, 1, 1);
	}
	
	function line(ctx,color,p0,p1,p2/*etc*/) 
	{
		// assume no points
		if(arguments.length<3)
			return;
		// assume 1 point, instead call sphere
		else if(arguments.length==3)
			return;

		ctx.fillStyle = color;
		ctx.strokeStyle = color;
		
		// Draw Line
		ctx.beginPath();
		ctx.moveTo(arguments[2].x,arguments[2].y);
		for (var i = 3; i < arguments.length; i++)
		{
			ctx.lineTo(arguments[i].x,arguments[i].y);
		}
		ctx.stroke();
	}
	
	function save($this,urlSave) 
	{	
		var data = {json: JSON.stringify($this.data('history'))};
		$this.attr('saving',true);
		$.post(urlSave, data,
			function(data){
				$this.attr('saving',false);
		}, "json");
	}
	
	function load($this,urlLoad) 
	{
		var before = new Date();
		
		$.post(urlLoad, {},
			function(data){
				//alert(data.name); // John
				var after = new Date();
				//alert("It took 1/" + (1.0/((after.getUTCMilliseconds()-before.getUTCMilliseconds())/1000.0)) + "seconds");
				
				$this.clear();
				// replace history
				$this.data('history',data);
				
				for (key in data)
				{
					var color,oldX,oldY;
					for(ln in data[key])
					{
						if(ln==0)
							color = data[key][0];
						else if(ln==1)
						{
							oldX = data[key][1][0];
							oldY = data[key][1][1];
						}
						else
						{
							//debug(ln);
							var x = data[key][ln][0],
								y = data[key][ln][1];
							
							line($this.get(0).getContext("2d"),color,{x:oldX,y:oldY},{x:x,y:y});
							oldX=x;
							oldY=y;
						}
					}
				}
				
				//console.dir(data);
			//	console.log(data.time); //  2pm
		}, "json");
	}
	
	// public functions
	$.fn.clear = function(color) {
		return this.each(function() {
			$this = $(this);

			// use options if no clear color is passed in 		
			// TODO: Make it use the default colors correctly
			color = getAttribute($this,'clear',color);
				
			//debug(color);
			//console.log(this);
			
			clear(this.getContext("2d"),color,$this.attr('width'),$this.attr('height'));
		});
	};
	
	//
	// plugin defaults
	//
	$.fn.drawio.defaults = {
		width: 640,
		height: 480,
		clear: "rgba(0,0,0,255)",
		fill: "rgb(255,255,255)",
		urlSave: "",
		urlLoad: ""
	};
//
// end of closure
//
})(jQuery);